using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Xml;
using System.IO;

namespace Jonathan.Tabber
{
    public delegate void PageAddEventHandler(PageEventArgs e);
    public delegate void PageRemoveEventHandler(PageEventArgs e);
    public delegate void PageChangeEventHandler(PageEventArgs e);
    public delegate void TabPanelDoubleClickHandler (TabberGroup tabberGroup, MouseEventArgs e);
    public delegate TabberPage CreateTabberPageDel (string tabType, string tabTitle, string tabInfo);

	/// <summary>
	/// A Tab control that can group tabs.
	/// </summary>
    public partial class Tabber : UserControl
    {
        #region Variables and Such

        [DllImport("User32")]
        private static extern int ShowWindow(int hwnd, int nCmdShow);

        [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        static extern bool SetWindowPos(
            int hWnd,               // handle to window
            int hWndInsertAfter,    // placement-order handle
            int X,                  // horizontal position
            int Y,                  // vertical position
            int cx,                 // width
            int cy,                 // height
            uint uFlags             // window-positioning options
        );

        public enum TabDockStyle
        {
            Top,
            Left,
            Right,
            Bottom,
            Floating,
            Tab,
            None
        }

        public event PageAddEventHandler BeforePageAdd;
        public event PageAddEventHandler BeforePageClose;
        public event PageChangeEventHandler TabberPageChanged;
        public event TabPanelDoubleClickHandler TabPanelDoubleClick;

        private const int SW_SHOWNOACTIVATE = 4;
        private const int HWND_TOPMOST = -1;
        private const int SWP_NOACTIVATE = 0x0010;

        private bool m_Dragging;
        private bool m_CloseOnMiddle;
        private List<TabberGroup> m_TabGroups;
        private List<TabberGroup> m_FloatingGroups;
        private frmDockWindow m_DockWindow;
        private frmDockPositioner m_DockPositioner;
        private Rectangle m_DefaultFloatingRec;
        private TabDockStyle m_DropPos;
        private TabberGroup m_DropGroup;
        private TabButton m_DropButton;
        private int m_DropIndex;
        private ContextMenuStrip m_TabMenuStrip = null;

        // Selected Tab Colors...
        private Color m_SelectedBaseColor;
        private Color m_SelectedButtonColor;
        private Color m_SelectedHighlightColor;
        private Color m_SelectedForeColor;

        // UnSelected Tab Colors...
        private Color m_UnSelectedBaseColor;
        private Color m_UnSelectedButtonColor;
        private Color m_UnSelectedGlowColor;
        private Color m_UnSelectedHighlightColor;
        private Color m_UnSelectedForeColor;

        #endregion

		/// <summary>
		/// Creates a new Tabber Control.
		/// </summary>
        public Tabber()
        {

            this.m_SelectedBaseColor = Color.Transparent;
            this.m_SelectedButtonColor = Color.Gray;
            this.m_SelectedForeColor = Color.Black;
            this.m_SelectedHighlightColor = Color.White;

            this.m_UnSelectedBaseColor = Color.Transparent;
            this.m_UnSelectedButtonColor = Color.DarkGray;
            this.m_UnSelectedForeColor = Color.Black;
            this.m_UnSelectedHighlightColor = Color.White;
            this.m_UnSelectedGlowColor = Color.Transparent;

            this.m_TabGroups = new List<TabberGroup>();
            this.m_FloatingGroups = new List<TabberGroup>();
            this.m_TabGroups.Add(new TabberGroup(this));
            this.Controls.Add(m_TabGroups[0]);
            this.Dock = DockStyle.Fill;
            this.m_Dragging = false;
            this.m_CloseOnMiddle = true;

            this.m_DockWindow = new frmDockWindow();
            this.m_DockPositioner = new frmDockPositioner();
            this.m_DockPositioner.TopLevel = true;
            this.m_DefaultFloatingRec = new Rectangle(12, 12, 300, 300);
            this.m_DropPos = TabDockStyle.None;
            this.m_DropIndex = -1;

            this.BeforePageAdd += new PageAddEventHandler(Tabber_BeforePageAdd);
            this.BeforePageClose += new PageAddEventHandler(Tabber_BeforePageClose);
            this.TabberPageChanged += new PageChangeEventHandler(Tabber_TabberPageChanged);
            this.TabPanelDoubleClick += new TabPanelDoubleClickHandler(Tabber_TabPanelDoubleClick);

            InitializeComponent();
        }

        #region -= Properties =-

        /// <summary>
        /// Gets or Set if we should close the tabs when they are click with the middle mouse button...
        /// </summary>
        [Category("Tabber"),
        Description("Gets or Set if we should close the tabs when they are click with the middle mouse button.")]
        public bool CloseTabsOnMiddleMouseClick
        {
            get { return this.m_CloseOnMiddle; }
            set { this.m_CloseOnMiddle = value; }
        }

        /// <summary>
        /// Gets or Sets the base color of the selected tab...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "Transparent"),
         Description("The backing for the tab.")]
        public Color SelectedTabBaseColor
        {
            get { return this.m_SelectedBaseColor; }

            set { this.m_SelectedBaseColor = value; }
        }

        /// <summary>
        /// Gets or Sets the Main color of the selected tab...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "Gray"),
         Description("The Main for the tab.")]
        public Color SelectedTabMainColor
        {
            get { return this.m_SelectedButtonColor; }

            set { this.m_SelectedButtonColor = value; }
        }

        /// <summary>
        /// Gets or Sets the Highlight color of the selected tab...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "White"),
         Description("The Highlighting for the tab.")]
        public Color SelectedTabHighlightColor
        {
            get { return this.m_SelectedHighlightColor; }

            set { this.m_SelectedHighlightColor = value; }
        }

        /// <summary>
        /// Gets or Sets the ForeColor of the selected tab...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "Black"),
         Description("The Text Color the tab.")]
        public Color SelectedTabForeColor
        {
            get { return this.m_SelectedForeColor; }

            set { this.m_SelectedForeColor = value; }
        }

        /// <summary>
        /// Gets or Sets the base color of the unselected tabs...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "Transparent"),
         Description("The backing for the tab.")]
        public Color UnSelectedTabBaseColor
        {
            get { return this.m_UnSelectedBaseColor; }

            set { this.m_UnSelectedBaseColor = value; }
        }

        /// <summary>
        /// Gets or Sets the Glow color of the unselected tabs...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "Transparent"),
         Description("The backing for the tab.")]
        public Color UnSelectedTabGlowColor
        {
            get { return this.m_UnSelectedGlowColor; }

            set { this.m_UnSelectedGlowColor = value; }
        }

        /// <summary>
        /// Gets or Sets the Main color of the unselected tabs...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "DarkGray"),
         Description("The Main for the tab.")]
        public Color UnSelectedTabMainColor
        {
            get { return this.m_UnSelectedButtonColor; }

            set { this.m_UnSelectedButtonColor = value; }
        }

        /// <summary>
        /// Gets or Sets the Highlight color of the unselected tabs...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "White"),
         Description("The Highlighting for the tab.")]
        public Color UnSelectedTabHighlightColor
        {
            get { return this.m_UnSelectedHighlightColor; }

            set { this.m_UnSelectedHighlightColor = value; }
        }

        /// <summary>
        /// Gets or Sets the ForeColor of the unselected tabs...
        /// </summary>
        [Category("Appearance"),
         DefaultValue(typeof(Color), "Black"),
         Description("The Text Color the tab.")]
        public Color UnSelectedTabForeColor
        {
            get { return this.m_UnSelectedForeColor; }

            set { this.m_UnSelectedForeColor = value; }
        }

        /// <summary>
        /// Gets or Sets the Context Menu Strip for the Tabs...
        /// </summary>
        [Category("Tabber"),
         Description("The ContextMenuStrip to display when tabs are right-clicked.")]
        public ContextMenuStrip TabContextMenuStrip
        {
            get { return this.m_TabMenuStrip; }

            set { this.m_TabMenuStrip = value; }
        }

        #endregion

        #region -= Events =-

        internal void SetRemoveEvent(PageEventArgs pe)
        {
            BeforePageClose(pe);
        }

        internal void SetPageChange(PageEventArgs pe)
        {
            TabberPageChanged(pe);
        }

        internal void CallTabPanelDoubleClick(TabberGroup tabberGroup, MouseEventArgs e)
        {
            TabPanelDoubleClick(tabberGroup, e);
        }

        internal void Tabber_BeforePageAdd(PageEventArgs pe)
        {
        }

        internal void Tabber_BeforePageClose(PageEventArgs pe)
        {
        }

        internal void Tabber_TabberPageChanged(PageEventArgs pe)
        {
        }

        internal void Tabber_TabPanelDoubleClick(TabberGroup tabberGroup, MouseEventArgs e)
        {
        }

        #endregion

        internal bool Dragging
        {
            get { return this.m_Dragging; }
        }

        internal void SetToolTip(Control ctrl, string text)
        {
            ttMain.SetToolTip(ctrl, text);
        }

        /// <summary>
        /// Adds a TabberPage to the primary TabberGroup...
        /// </summary>
        /// <param name="tab">TabberPage to add</param>
        public void AddTab(TabberPage tab)
        {
            BeforePageAdd(new PageEventArgs(tab));
            TabberGroup grp = m_TabGroups[0];
            grp.AddTab(tab);
        }

        /// <summary>
        /// Adds a TabberPage to the specified group...
        /// </summary>
        /// <param name="tab">TabberPage to add</param>
        /// <param name="groupIndex">Index of TabberGroup to add page to</param>
        public void AddTab(TabberPage tab, int groupIndex)
        {
            BeforePageAdd(new PageEventArgs(tab));
            if (groupIndex < this.m_TabGroups.Count)
            {
                TabberGroup grp = m_TabGroups[groupIndex];
                grp.AddTab(tab);
            }
        }

        /// <summary>
        /// Adds a TabberPage to the specified group...
        /// </summary>
        /// <param name="tab">TabberPage to add</param>
        /// <param name="group">TabberGroup to add page to</param>
        public void AddTab(TabberPage tab, TabberGroup group)
        {
            BeforePageAdd(new PageEventArgs(tab));
            for (int a = 0; a < this.m_TabGroups.Count; a++)
            {
                TabberGroup grp = m_TabGroups[a];
                if (grp == group)
                {
                    grp.AddTab(tab);
                    break;
                }
            }
        }

        /// <summary>
        /// Gets the TabberGroups of the Tabber Control...
        /// </summary>
        public List<TabberGroup> TabGroups
        {
            get
            {
                /*TabberGroup[] groups = new TabberGroup[this.m_TabGroups.Count];
                for (int a = 0; a < this.m_TabGroups.Count; a++)
                {
                    groups[a] = this.m_TabGroups[a];
                }*/

                return this.m_TabGroups;
            }
        }

        /// <summary>
        /// Gets the Floating TabberGroups of the Tabber Control...
        /// </summary>
        public List<TabberGroup> FloatingTabGroups
        {
            get
            {
                /*TabberGroup[] groups = new TabberGroup[this.m_FloatingGroups.Count];
                for (int a = 0; a < this.m_FloatingGroups.Count; a++)
                {
                    groups[a] = this.m_FloatingGroups[a];
                }*/

                return this.m_FloatingGroups;
            }
        }

        #region -= Start Drag =-

        /// <summary>
        /// Starts the Drag Operation
        /// </summary>
        /// <param name="btn">Tab Button to drag</param>
        internal void StartDrag(TabButton btn)
        {
            if (!m_Dragging)
            {
                this.m_DropButton = btn;

                Bitmap bmp = new Bitmap(btn.Width, btn.Height);
                Graphics g = Graphics.FromImage(bmp);
                btn.PaintDragImage(g);

                // Start the drag...
                this.Cursor = new Cursor(bmp.GetHicon());
                if (btn.Page.Group.Floating != null)
                {
                    btn.Page.Group.Floating.Cursor = this.Cursor;
                }
                g.Dispose();
                this.m_Dragging = true;
				bmp.Dispose();

                this.m_DockPositioner.SetText("");
                ShowWindow(this.m_DockPositioner.Handle.ToInt32(), 4);
            }
        }

        #endregion

        #region -= Drag Move =-

        /// <summary>
        /// Moves the Drag Operation...
        /// </summary>
        /// <param name="p">Screen Point of Mouse</param>
        /// <param name="x">X of the Client Tab Click</param>
        /// <param name="y">Y of the Client Tab Click</param>
        internal void DragMove(Point p, int x, int y)
        {
            if (!this.CheckDrag(p, x, y, this.m_FloatingGroups))
            {
                this.CheckDrag(p, x, y, this.m_TabGroups);
            }
        }

        private bool CheckDrag(Point p, int x, int y, List<TabberGroup> tabs)
        {
            Point cPoint = this.PointToClient(p);
            // DragHelper.ImageList_DragMove(x, y);
            for (int a = 0; a < tabs.Count; a++)
            {
                TabberGroup grp = tabs[a];
                Point pnt = grp.PointToScreen(new Point(grp.Left, grp.Top));
                if (p.X > pnt.X && p.X < pnt.X + grp.Width && p.Y > pnt.Y && p.Y < pnt.Y + grp.Height)
                {
                    // Set the drop group...
                    this.m_DropGroup = grp;

                    int left = (pnt.X + grp.Bounds.Width / 2) - this.m_DockPositioner.Width / 2;
                    int top = (pnt.Y + grp.Bounds.Height / 2) - this.m_DockPositioner.Height / 2;

                    if (this.m_DockPositioner.Left != left || this.m_DockPositioner.Top != top)
                    {
                        SetWindowPos(this.m_DockPositioner.Handle.ToInt32(), 0, left, top, this.m_DockPositioner.Width,
                            this.m_DockPositioner.Height, SWP_NOACTIVATE);
                    }

                    if (p.Y < grp.TabHeight + pnt.Y)
                    {
                        this.m_DockWindow.BackColor = Color.MistyRose;
                        //this.m_DockWindow.Opacity = 1;

                        System.Reflection.Assembly assem;
                        assem = this.GetType().Assembly;
                        System.Resources.ResourceManager mngr = new System.Resources.ResourceManager("Jonathan.Tabber.InternalImages", assem);
                        Image arrow = (Image)mngr.GetObject("uparrow");
                        this.m_DockWindow.BackgroundImage = arrow;
                        this.m_DockWindow.BackgroundImageLayout = ImageLayout.Center;
                        this.m_DockWindow.Invalidate(true);

                        Point tPoint = grp.TabButtons[0].Parent.PointToClient(p);
                        int l = 0, r = 0, w = 0;
                        for (int z = 0; z < grp.TabButtons.Count; z++)
                        {
                            if (z == 0)
                            {
                                l = -10; 
                                r = 10;
                            }
                            else
                            {
                                l = grp.TabButtons[z].Left - 10;
                                r = grp.TabButtons[z].Right + 10;
                                w += grp.TabButtons[z].Width;
                            }

                            if (tPoint.X > (l - 10) & tPoint.X < (r - 15))
                            {
                                int add = (z == 0) ? 4 : 0;
                                SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, grp.TabButtons[0].Parent.PointToScreen(new Point(l, 0)).X + add,
                                    grp.TabButtons[0].Parent.PointToScreen(new Point(l, 0)).Y + grp.TabHeight, 16, 17, SWP_NOACTIVATE);
                                ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                                this.m_DropPos = TabDockStyle.Tab;
                                this.m_DropIndex = z;
                                return true;
                            }
                        }
                        if (tPoint.X > (w) + (6 * grp.TabButtons.Count) - 10)
                        {
                            l = grp.TabButtons[grp.TabButtons.Count - 1].Right;
                            SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, grp.TabButtons[0].Parent.PointToScreen(new Point(l, 0)).X - 3,
                                grp.TabButtons[0].Parent.PointToScreen(new Point(l, 0)).Y + grp.TabHeight, 16, 17, SWP_NOACTIVATE);
                            ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                            this.m_DropPos = TabDockStyle.Tab;
                            this.m_DropIndex = grp.TabButtons.Count;
                            return true;
                        }
                        if (this.m_DockWindow.Visible)
                        {
                            this.m_DockWindow.Hide();
                            this.m_DockPositioner.SetText("");
                        }
                        this.m_DropPos = TabDockStyle.None;
                    }
                    else
                    {
                        if (grp.TabButtons.Count == 1 && grp.TabButtons[0] == this.m_DropButton)
                        {
                            this.m_DropPos = TabDockStyle.None;
                            return true;
                        }
                        Point dPoint = this.m_DockPositioner.PointToClient(p);
                        this.m_DockWindow.BackColor = Color.SteelBlue;
                        this.m_DockWindow.BackgroundImage = null;
                        //this.m_DockWindow.Opacity = 0.4;
                        if (dPoint.X > 0 && dPoint.X < 30 && dPoint.Y > 33 && dPoint.Y < 63)
                        {
                            SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, pnt.X, pnt.Y,
                                grp.Width / 2, grp.Height, SWP_NOACTIVATE);
                            ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                            this.m_DropPos = TabDockStyle.Left;
                            this.m_DockPositioner.SetText("Dock to Left");
                            return true;
                        }
                        else if (dPoint.X > 33 && dPoint.Y < 30 && dPoint.X < 63 && dPoint.Y > 0)
                        {
                            SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, pnt.X, pnt.Y,
                                grp.Width, grp.Height / 2, SWP_NOACTIVATE);
                            ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                            this.m_DropPos = TabDockStyle.Top;
                            this.m_DockPositioner.SetText("Dock to Top");
                            return true;
                        }
                        else if (dPoint.X > 33 && dPoint.Y > 65 && dPoint.X < 63 && dPoint.Y < 94)
                        {
                            SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, pnt.X, pnt.Y + (grp.Height / 2),
                                grp.Width, grp.Height / 2, SWP_NOACTIVATE);
                            ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                            this.m_DropPos = TabDockStyle.Bottom;
                            this.m_DockPositioner.SetText("Dock to Bottom");
                            return true;
                        }
                        else if (dPoint.X > 65 && dPoint.Y > 33 && dPoint.Y < 63 && dPoint.X < 94)
                        {
                            SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, pnt.X + (grp.Width / 2),
                                pnt.Y, grp.Width / 2, grp.Height, SWP_NOACTIVATE);
                            ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                            this.m_DropPos = TabDockStyle.Right;
                            this.m_DockPositioner.SetText("Dock to Right");
                            return true;
                        }
                        else if (dPoint.X < 63 && dPoint.X > 33 && dPoint.Y > 33 && dPoint.Y < 63)
                        {
                            SetWindowPos(this.m_DockWindow.Handle.ToInt32(), HWND_TOPMOST, this.m_DefaultFloatingRec.Left,
                                this.m_DefaultFloatingRec.Top, this.m_DefaultFloatingRec.Width, this.m_DefaultFloatingRec.Height,
                                SWP_NOACTIVATE);
                            ShowWindow(this.m_DockWindow.Handle.ToInt32(), 4);
                            this.m_DropPos = TabDockStyle.Floating;
                            this.m_DockPositioner.SetText("Make floating");
                            return true;
                        }
                        else
                        {
                            this.m_DropPos = TabDockStyle.None;
                            if (this.m_DockWindow.Visible)
                            {
                                this.m_DockWindow.Hide();
                                this.m_DockPositioner.SetText("");
                            }
                        }
                    }
                    return true;
                }
            }
            return false;
        }

        #endregion

        #region End Drag

        /// <summary>
        /// Stops the current drag, and handles data...
        /// </summary>
        internal void EndDrag()
        {
            // Hide the Dock window...
            if (this.m_DockWindow.Visible)
            {
                this.m_DockWindow.Hide();
                this.m_DockPositioner.SetText("");
            }

            // Reset the floating window cursor...
            if (this.m_DropButton.Page.Group.Floating != null)
            {
                this.m_DropButton.Page.Group.Floating.Cursor = Cursors.Default;
            }

            // End the dragging...
            this.m_Dragging = false;
            this.Cursor = Cursors.Default;

            // Remove the Drag Image...
            //DragHelper.ImageList_EndDrag();
            //DragHelper.ImageList_DragLeave(this.Handle);

            // Hide the dock positioner form...
            this.m_DockPositioner.Hide();

            // Handle the drop...
            if (this.m_DropPos != TabDockStyle.None && this.m_DropPos != TabDockStyle.Tab &&
                this.m_DropPos != TabDockStyle.Floating)
            {
                AddTab(this.m_DropGroup, this.m_DropButton.Page, this.m_DropPos);
            }
            else if (this.m_DropPos == TabDockStyle.Tab)
            {
                if (this.m_DropGroup != this.m_DropButton.Page.Group)
                {
                    this.m_DropButton.Page.Group.RemoveTab(this.m_DropButton.Page);
                    this.m_DropGroup.AddTab(this.m_DropButton.Page);
                }
                this.m_DropGroup.ReorderTab(this.m_DropButton, this.m_DropIndex);
            }
            else if (this.m_DropPos == TabDockStyle.Floating)
            {
                // We need to create a new group...
                TabberGroup newGroup = new TabberGroup(this);
                Control ctrl = this.m_DropGroup.Parent;

                this.m_DropButton.Page.Group.RemoveTab(this.m_DropButton.Page);
                newGroup.AddTab(this.m_DropButton.Page);

                frmFloatingGroup frm = new frmFloatingGroup(this);
                newGroup.Floating = frm;
                frm.Text = this.m_DropButton.ButtonText;
                this.m_FloatingGroups.Add(newGroup);
                frm.Controls.Add(newGroup);
                frm.Size = this.m_DefaultFloatingRec.Size;
                frm.Location = this.m_DefaultFloatingRec.Location;
                frm.AddGroup(newGroup);
                frm.Show();
            }
        }

        /// <summary>
        /// Adds the tabberpage to the group in the given position...
        /// </summary>
        /// <param name="addGroup">Group to Add Tab to.</param>
        /// <param name="pagetoAdd">TabberPage to Add.</param>
        /// <param name="pos">Position to Add...</param>
        public void AddTab (TabberGroup addGroup, TabberPage pagetoAdd, TabDockStyle pos)
        {
            //this.SuspendLayout();
            if (addGroup.Parent.GetType() == typeof(SplitterPanel))
            {
                SplitterPanel sp = addGroup.Parent as SplitterPanel;
                if (sp.Tag.ToString().Equals("1") && pagetoAdd.Group == null)
                {
                    SplitContainer sc = addGroup.Parent.Parent as SplitContainer;
                    if (sc.Panel2.Controls.Count > 0)
                    {
                        if (sc.Panel2.Controls[0].GetType() != typeof(SplitContainer))
                        {
                            TabberGroup tg = sc.Panel2.Controls[0] as TabberGroup;
                            tg.AddTab(pagetoAdd);
                            //this.ResumeLayout();
                            return;
                        }
                    }
                }
            }
            
            // We need to create a new group...
            TabberGroup newGroup = new TabberGroup(this);
            Control ctrl = addGroup.Parent;
            this.m_TabGroups.Add(newGroup);
            newGroup.Floating = addGroup.Floating;
            if (addGroup.Floating != null)
                addGroup.Floating.AddGroup(newGroup);

            // Create a splitcontainer...
            SplitContainer spc = new SplitContainer();
            spc.Dock = DockStyle.Fill;
            spc.Panel1.Tag = "1";
            spc.Panel2.Tag = "2";
            int w = spc.SplitterDistance;

            // Re-arrange controls...
            ctrl.Controls.Remove(addGroup);
            ctrl.Controls.Add(spc);
            if(pagetoAdd.Group != null)
                pagetoAdd.Group.RemoveTab(pagetoAdd);
            newGroup.AddTab(pagetoAdd);

            switch (pos)
            {
                case TabDockStyle.Left:
                    w = addGroup.Width / 2;
                    spc.Panel1.Controls.Add(newGroup);
                    spc.Panel2.Controls.Add(addGroup);
                    break;
                case TabDockStyle.Top:
                    w = addGroup.Height / 2;
                    spc.Orientation = Orientation.Horizontal;
                    spc.Panel1.Controls.Add(newGroup);
                    spc.Panel2.Controls.Add(addGroup);
                    break;
                case TabDockStyle.Bottom:
                    w = addGroup.Height / 2;
                    spc.Orientation = Orientation.Horizontal;
                    spc.Panel2.Controls.Add(newGroup);
                    spc.Panel1.Controls.Add(addGroup);
                    break;
                case TabDockStyle.Right:
                    w = addGroup.Width / 2;
                    spc.Panel2.Controls.Add(newGroup);
                    spc.Panel1.Controls.Add(addGroup);
                    break;
            }
            spc.SplitterDistance = w;
            //this.ResumeLayout();
        }

        #endregion

        #region Remove Group

        /// <summary>
        /// Removes a TabberGroup from the Control, it will not remove the group if it is the only one...
        /// </summary>
        /// <param name="group">Group to be removed</param>
        public void RemoveGroup(TabberGroup group)
        {
            if (group.Floating != null)
            {
                for (int a = 0; a < this.m_FloatingGroups.Count; a++)
                {
                    if (group == this.m_FloatingGroups[a])
                    {
                        group.Floating.RemoveGroup(group);
                        this.m_FloatingGroups.Remove(group);
                        break;
                    }
                }

                if (group.Parent != null)
                {
                    if (group.Parent.GetType() == new frmFloatingGroup(this).GetType())
                    {
                        frmFloatingGroup frm = (frmFloatingGroup)group.Parent;
                        frm.Controls.Remove(group);
                        frm.Close();
                        return;
                    }
                }
                else
                {
                    return;
                }

                SplitContainer spc = (SplitContainer)group.Parent.Parent;
                string str = group.Parent.Tag.ToString();
                group.Parent.Controls.Remove(group);
                group.Dispose();
                Control ctrl;
                if (str == "1")
                {
                    ctrl = spc.Panel2.Controls[0];
                }
                else
                {
                    ctrl = spc.Panel1.Controls[0];
                }
                spc.Parent.Controls.Add(ctrl);
                spc.Parent.Controls.Remove(spc);
                spc.Dispose();
            }
            else
            {
                if (this.m_TabGroups.Count > 1)
                {
                    for (int a = 0; a < this.m_TabGroups.Count; a++)
                    {
                        if (group == this.m_TabGroups[a])
                        {
                            this.m_TabGroups.Remove(group);
                            break;
                        }
                    }

                    SplitContainer spc = (SplitContainer)group.Parent.Parent;
                    string str = group.Parent.Tag.ToString();
                    group.Parent.Controls.Remove(group);
                    group.Dispose();
                    Control ctrl;
                    if (str == "1")
                    {
                        ctrl = spc.Panel2.Controls[0];
                    }
                    else
                    {
                        ctrl = spc.Panel1.Controls[0];
                    }
                    spc.Parent.Controls.Add(ctrl);
                    spc.Parent.Controls.Remove(spc);
                    spc.Dispose();
                }
            }
        }

        #endregion

        #region Save Layout

        /// <summary>
        /// Saves the Tabber Layout to a xml file...
        /// </summary>
        /// <param name="filePath">File to save to.</param>
        public void SaveLayout (string filePath)
        {
            try
            {
                /*if (File.Exists(filePath))
                    File.Delete(filePath);*/
                
                XmlTextWriter xmlOut = new XmlTextWriter(new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite), System.Text.Encoding.Unicode);
                xmlOut.Indentation = 3;
                xmlOut.Formatting = Formatting.Indented;
                xmlOut.WriteStartDocument();
                xmlOut.WriteStartElement("Tabber");

                if (this.Controls[0].GetType() == typeof(TabberGroup))
                {
                    // We only have one group...
                    WriteTabberGroup(xmlOut, this.m_TabGroups[0]);
                }
                else
                {
                    WriteContainer(xmlOut, this.Controls[0] as SplitContainer);
                }

                xmlOut.WriteEndElement();
                xmlOut.Close();
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Writes the information for a tabber group...
        /// </summary>
        /// <param name="xmlOut">Output Stream</param>
        /// <param name="tg">Tabber group</param>
        private static void WriteTabberGroup (XmlTextWriter xmlOut, TabberGroup tg)
        {
            xmlOut.WriteStartElement("TabberGroup");
            foreach (TabberPage tp in tg.Tabs)
            {
                xmlOut.WriteStartElement("TabberPage");
                xmlOut.WriteAttributeString("TabTitle", tp.TabTitle);
                xmlOut.WriteAttributeString("TabType", tp.GetType().ToString());
                xmlOut.WriteAttributeString("TabInfo", tp.GetPageInfo());
                xmlOut.WriteEndElement();
            }
            xmlOut.WriteEndElement();
        }

        /// <summary>
        /// Writes the information for a splitter...
        /// </summary>
        /// <param name="xmlOut">Output Stream</param>
        /// <param name="tg">Splitter</param>
        private static void WriteContainer (XmlTextWriter xmlOut, SplitContainer split)
        {
            xmlOut.WriteStartElement("SplitContainer");
            xmlOut.WriteAttributeString("SplitType", split.Orientation.ToString());
            xmlOut.WriteAttributeString("SplitDist", split.SplitterDistance.ToString());

            xmlOut.WriteStartElement("Panel1");
            if (split.Panel1.Controls[0].GetType() == typeof(TabberGroup))
            {
                WriteTabberGroup(xmlOut, split.Panel1.Controls[0] as TabberGroup);
            }
            else
            {
                WriteContainer(xmlOut, split.Panel1.Controls[0] as SplitContainer);
            }
            xmlOut.WriteEndElement();

            xmlOut.WriteStartElement("Panel2");
            if (split.Panel1.Controls[0].GetType() == typeof(TabberGroup))
            {
                WriteTabberGroup(xmlOut, split.Panel2.Controls[0] as TabberGroup);
            }
            else
            {
                WriteContainer(xmlOut, split.Panel2.Controls[0] as SplitContainer);
            }
            xmlOut.WriteEndElement();

            xmlOut.WriteEndElement();
        }

        #endregion

        #region Load Layout

        /// <summary>
        /// Loads the given tab layout...
        /// </summary>
        /// <param name="filePath">File with layout saved...</param>
        /// <param name="del">LoadTabDelegate Method.</param>
        public bool LoadLayout (string filePath, CreateTabberPageDel del)
        {
            if (!File.Exists(filePath))
                return false;

            XmlTextReader xmlIn = new XmlTextReader(filePath);
            xmlIn.WhitespaceHandling = WhitespaceHandling.None;
            TabberGroup currGroup = null;
            SplitContainer curSplit = null;
            bool panel1 = false;
            int dist = 100;
            this.m_TabGroups.Clear();
            this.Controls.Clear();

            while (xmlIn.Read())
            {
                if (xmlIn.NodeType == XmlNodeType.Element)
                {
                    if (xmlIn.Name.Equals("SplitContainer"))
                    {
                        SplitContainer spc = new SplitContainer();
                        string oren = xmlIn.GetAttribute("SplitType");
                        dist = Convert.ToInt32(xmlIn.GetAttribute("SplitDist"));
                        if (oren == Orientation.Horizontal.ToString())
                        {
                            spc.Orientation = Orientation.Horizontal;
                        }
                        spc.Dock = DockStyle.Fill;
                        spc.Panel1.Tag = "1";
                        spc.Panel2.Tag = "2";
                        if (curSplit == null)
                        {
                            this.Controls.Add(spc);
                        }
                        else if (panel1)
                        {
                            curSplit.Panel1.Controls.Add(spc);
                        }
                        else
                        {
                            curSplit.Panel2.Controls.Add(spc);
                        }
                        curSplit = spc;
                    }
                    else if (xmlIn.Name.Equals("Panel1"))
                    {
                        panel1 = true;
                    }
                    else if (xmlIn.Name.Equals("Panel2"))
                    {
                        panel1 = false;
                    }
                    else if (xmlIn.Name.Equals("TabberGroup"))
                    {
                        TabberGroup newGroup = new TabberGroup(this);
                        if (curSplit == null)
                        {
                            this.Controls.Add(newGroup);
                        }
                        else if (panel1)
                        {
                            curSplit.Panel1.Controls.Add(newGroup);
                        }
                        else
                        {
                            curSplit.Panel2.Controls.Add(newGroup);
                        }
                        currGroup = newGroup;
                        this.m_TabGroups.Add(newGroup);
                    }
                    else if (xmlIn.Name.Equals("TabberPage"))
                    {
                        currGroup.AddTab(del(xmlIn.GetAttribute("TabType"), xmlIn.GetAttribute("TabTitle"), xmlIn.GetAttribute("TabInfo")));
                    }
                }
                else if (xmlIn.NodeType == XmlNodeType.EndElement)
                {
                    if (xmlIn.Name.Equals("Panel2"))
                    {
                        curSplit.SplitterDistance = dist;
                        if (curSplit.Parent != null)
                        {
                            if (curSplit.Parent.Tag != null)
                            {
                                if (curSplit.Parent.Tag.ToString() == "1" || curSplit.Parent.Tag.ToString() == "2")
                                {
                                    curSplit = curSplit.Parent.Parent as SplitContainer;
                                }
                            }
                        }
                    }
                }
            }
            return true;
        }

        #endregion
    }
}